# -*-coding: Utf-8 -*-
# @File : main .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time：2023/9/30

from typing import List

import requests
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks, Request
from fastapi.templating import Jinja2Templates
from pydantic import HttpUrl
from sqlalchemy.orm import Session
from starlette import status
from coronavirus import curd, schemas
from coronavirus.database import engine, Base, SessionLocal
from coronavirus.models import City, Data

# 创建子路由
application = APIRouter()

# 创建前端页面配置
templates = Jinja2Templates(directory='./coronavirus/templates')

# 初始化数据库引擎对象
Base.metadata.create_all(bind=engine)


# 创建子依赖对象
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


# 创建城市
@application.post('/create_city', response_model=schemas.ReadCity)
async def create_city(city: schemas.CreateCity, db: Session = Depends(get_db)):
    '''

    :param city: 前端传入的符合 CreateCity 格式的城市数据
    :param db: 数据库操作对象，基于子依赖的数据库操作
    :return:
    '''
    # 判断是否存在当前城市 --- 根据前端传入的城市名字进行过滤
    db_city = curd.get_city_by_name(db=db, name=city.province)
    # 存在则主动抛出异常
    if db_city:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail='City is already registered!'
        )
    # 不存在则创建
    return curd.create_city(db=db, city=city)


# 查询城市数据
@application.get('/get_city/{city}', response_model=schemas.ReadCity)
async def get_city(city: str, db: Session = Depends(get_db)):
    '''

    :param city: 路径参数，路径中的城市名
    :param db: 数据库对象，依赖子依赖
    :return:
    '''
    # 使用数据库对象查询数据
    db_city = curd.get_city_by_name(db=db, name=city)
    # 校验数据是否存在
    if db_city is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail='City not found!'
        )
    # 数据存在
    return db_city


# 查询多个城市的数据
@application.get('/get_cities', response_model=List[schemas.ReadCity])
async def get_cities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    '''

    :param skip: 起始位置
    :param limit: 结束位置
    :param db: 数据库对象，依赖子依赖
    :return:
    '''
    cities = curd.get_cities(db=db, skip=skip, limit=limit)

    return cities


# 创建数据
@application.post('/create_data', response_model=schemas.ReadData)
async def create_data_for_city(city: str, data: schemas.CreateData, db: Session = Depends(get_db)):
    '''

    :param city: 给那个城市创建数据
    :param data: 城市的详细数据
    :param db: 数据库对象，依赖子依赖
    :return:
    '''
    # 查询当前城市是否存在
    db_city = curd.get_city_by_name(db=db, name=city)
    # 创建数据
    data = curd.create_city_data(db=db, data=data, city_id=db_city.id)
    return data


# 获取数据
@application.get('/get_data')
async def get_data(city: str = None, skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    '''

    :param city: 城市名字
    :param skip: 起始位置
    :param limit: 截止位置
    :param db: 数据库对象，依赖子依赖
    :return:
    '''
    data = curd.get_data(city=city, skip=skip, limit=limit, db=db)
    return data


# 测试定义根路径首页页面路由
# @application.get('/')
# async def coronavirus(request: Request, city: str = None, skip: int = 0, limit: int = 10,
#                       db: Session = Depends(get_db)):
#     # 查询数据
#     data = curd.get_data(city=city, skip=skip, limit=limit, db=db)
#     return templates.TemplateResponse(
#         # 前端页面文件名
#         "home.html",
#         {
#             # 请求对象
#             "request": request,
#             # 查询到的数据
#             "data": data,
#             # 回调 uRL
#             "sync_data_url": "/coronavirus/sync_coronavirus_data/jhu"
#         }
#     )


def bg_task(url: HttpUrl, db: Session):
    """这里注意一个坑，不要在后台任务的参数中db: Session = Depends(get_db)这样导入依赖"""
    # 利用 requests 请求第三方数据
    city_data = requests.get(url=f"{url}?source=jhu&country_code=CN&timelines=false")

    # 判断请求是否成功
    if 200 == city_data.status_code:
        # 同步数据前先清空原有的数据
        # City 表模型类
        db.query(City).delete()
        # 遍历每个城市的数据
        for location in city_data.json()["locations"]:
            # 构建数据格式
            city = {
                "province": location["province"],
                "country": location["country"],
                "country_code": "CN",
                "country_population": location["country_population"]
            }
            # 创建数据
            curd.create_city(db=db, city=schemas.CreateCity(**city))

    #  利用 requests 请求第三方数据
    coronavirus_data = requests.get(url=f"{url}?source=jhu&country_code=CN&timelines=true")

    # 判断请求是否成功
    if 200 == coronavirus_data.status_code:
        # Data 表模型类
        db.query(Data).delete()
        # 遍历数据
        for city in coronavirus_data.json()["locations"]:
            # 获取到城市对象
            db_city = curd.get_city_by_name(db=db, name=city["province"])
            # 存在则遍历数据
            for date, confirmed in city["timelines"]["confirmed"]["timeline"].items():
                data = {
                    "date": date.split("T")[0],  # 把'2020-12-31T00:00:00Z' 变成 ‘2020-12-31’
                    "confirmed": confirmed,
                    "deaths": city["timelines"]["deaths"]["timeline"][date],
                    "recovered": 0  # 每个城市每天有多少人痊愈，这种数据没有
                }
                # 这个city_id是city表中的主键ID，不是coronavirus_data数据里的ID
                curd.create_city_data(db=db, data=schemas.CreateData(**data), city_id=db_city.id)


@application.get("/sync_coronavirus_data/jhu")
def sync_coronavirus_data(background_tasks: BackgroundTasks, db: Session = Depends(get_db)):
    """从Johns Hopkins University同步COVID-19数据"""
    # 添加后台任务
    background_tasks.add_task(bg_task, "https://coronavirus-tracker-api.herokuapp.com/v2/locations", db)
    # 弹出框中的提示信息
    return {"message": "正在后台同步数据..."}


# 定义根路由逻辑
@application.get("/")
def coronavirus(request: Request, city: str = None, skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    # 从数据库获取到数据
    data = curd.get_data(db, city=city, skip=skip, limit=limit)
    # 渲染到页面上
    return templates.TemplateResponse("home.html", {
        "request": request,
        "data": data,
        "sync_data_url": "/coronavirus/sync_coronavirus_data/jhu"
    })
